package com.lsh.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.List;

/**
 * @author ：LiuShihao
 * @date ：Created in 2021/8/25 1:40 下午
 * @desc ：
 */
@Slf4j
@Component
public class AuthorizationFilter implements GlobalFilter, Ordered {

    /**存放公钥的文件名 */
    public String first_public = "first_public.txt";

    public String second_public = "second_public.txt";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("----------------------Gateway Global Filter Start---------------------------------");
        ServerHttpRequest request = exchange.getRequest();
        String uri = request.getURI().toString();
        log.info("URI: "+uri+" ; TIME : "+new Date().toString());
        if (uri.contains("/oauth/") || uri.contains("/storage/") || uri.contains("/account/")){
            // 请求认证服务   放行
            log.info("----------------------Gateway Global Filter 请求OAuth认证服务：放行！---------------------------------");
            return chain.filter(exchange);
        }

        HttpHeaders headers = request.getHeaders();
        //获取请求头中的认证信息
        List<String> authorization = headers.get("Authorization");
        if (authorization == null || authorization.isEmpty() || authorization.size()==0 || authorization.get(0).length()<8){
            //没有认证信息 不允许访问，禁止访问
            ServerHttpResponse response = exchange.getResponse();
            //返回401 未授权
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.info("----------------------Gateway Global Filter End: 没有令牌！----------------------------");
            return exchange.getResponse().setComplete();
        }
        // Bearer token
        String access_token = authorization.get(0);
        //注意：此处的JWT令牌是从access_token值第7位开始取值（不包括第7位）
        String jwtToken = access_token.substring(7);
        //公钥（读取public.txt的公钥信息）
        Resource resource = new ClassPathResource(first_public);
        String publicKey = null;
        try {
            publicKey =  inputStream2String(resource.getInputStream());

        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
        String claims =null;
        try{
            //解析 token 令牌
            Jwt jwt = JwtHelper.decodeAndVerify(jwtToken, new RsaVerifier(publicKey));
            //获取Jwt原始内容 载荷
            claims = jwt.getClaims();
            System.out.println(claims);
        }catch (Exception e){
            log.error("令牌解析失败："+e.getMessage());
            ServerHttpResponse response = exchange.getResponse();
            //返回401 未授权
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.info("----------------------Gateway Global Filter End:令牌解析失败！----------------------------");
            return exchange.getResponse().setComplete();
        }

        //添加请求头 信息
        ServerHttpRequest newRequest = request.mutate().header("username", claims).build();

        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();


        Mono<Void> filter = chain.filter(newExchange);
        log.info("----------------------Gateway Global Filter 令牌解析成功：放行！---------------------------------");
        return filter;
    }

    /**
     * 过滤器有一个优先级的问题，这个值越小，优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return -1;
    }

    public String inputStream2String(InputStream is) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(is));
        StringBuffer buffer = new StringBuffer();
        String line = "";
        while ((line = in.readLine()) != null) {
            buffer.append(line);
        }
        return buffer.toString();
    }

}
